﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using telWebBrowserNet.Lib.TeleDLL.Model;

namespace telWebBrowserNet.Lib.TeleDLL
{
    /// <summary>
    /// 电话盒子操作帮助类
    /// </summary>
    public class TeleHelper

    {
        static int pDeviceHandle;

        // 定义一个静态变量来保存类的实例
        private static TeleHelper uniqueInstance;
        // 定义一个标识确保线程同步
        private static readonly object locker = new object();
        // 定义私有构造函数，使外界不能创建该类实例
        private TeleHelper()
        {
        }
        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static TeleHelper GetInstance()
        {
            // 当第一个线程运行到这里时，此时会对locker对象 "加锁"，
            // 当第二个线程运行该方法时，首先检测到locker对象为"加锁"状态，该线程就会挂起等待第一个线程解锁
            // lock语句运行完之后（即线程运行完之后）会对该对象"解锁"
            // 双重锁定只需要一句判断就可以了
            if (uniqueInstance == null)
            {
                lock (locker)
                {
                    // 如果类的实例不存在则创建，否则直接返回
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new TeleHelper();
                    }
                }
            }
            return uniqueInstance;
        }
        /// <summary>
        /// 盒子句柄
        /// </summary>
        public static int PDeviceHandle { get => pDeviceHandle; set => pDeviceHandle = value; }

        /// <summary>
        /// 打开盒子，有人值守
        /// </summary>
        /// <returns></returns>
        public static TeleBaseModel StartBox()
        {
            TeleBaseModel teleBaseModel = new TeleBaseModel();
            int deviceCount = TeleHelper.GetDeviceCount();
            if (deviceCount <= 0)
            {
                teleBaseModel.Code = 11;
                teleBaseModel.Msg = " 当前可用设备个数：" + "0";
                return teleBaseModel;
            }
            int count = TeleHelper.OpenDevice(0);
            if (count == 0)
            {
                teleBaseModel.Code = 12;
                teleBaseModel.Msg = " 打开设备失败";
                return teleBaseModel;
            }
            int status = TeleHelper.GetDeviceStatus(count);
            if (status != 0)
            {
                teleBaseModel.Code = 12;
                teleBaseModel.Msg = "设备" + count + "异常，异常代码：" + status;
                return teleBaseModel;
            }
            pDeviceHandle = count;
            teleBaseModel.Code = 0;
            teleBaseModel.Msg = "设备正常";
            LogInfo.LogOutput(LogInfo.log_info, "设备" + count + "打开连接成功");

            //有人值守
            WriteModel writeModel = new WriteModel();
            writeModel.PDeviceHandle = pDeviceHandle;
            writeModel.addCommand("AdsMode", "Attended");
            writeModel.addCommand("checksum", "000000");
            LogInfo.LogOutput(LogInfo.log_info, "设置有人值守模式");
            ReadModel readModel = Execute(writeModel);
            if (readModel.Code != 0)
            {
                LogInfo.LogOutput(LogInfo.log_error, "读写出错" + readModel.Code);
                //出错流程
                if (readModel.Code == 1)
                {

                    Console.WriteLine("TeleWriteCode" + readModel.TeleWriteCode);
                    //Form1.Export_LogInfo("TeleWriteCode" + readModel.TeleWriteCode);
                }
                if (readModel.Code == 2)
                {
                    Console.WriteLine("TeleReadCode" + readModel.TeleReadCode);
                    //Form1.Export_LogInfo("TeleReadCode" + readModel.TeleReadCode);
                }
            }
            return teleBaseModel;
        }

        /// <summary>
        /// 获取支持的设备个数
        /// </summary>
        /// <returns>返回正整数表明存在设备，返回0表明不存在设备</returns>
        public static int GetDeviceCount()
        {
            return TeleDll.GetDeviceCount();
        }

        /// <summary>
        /// 根据设备索引号（nDeviceIndex）打开指定的USB设备
        /// </summary>
        /// <param name="nDeviceIndex"> 第一个设备的索引号为0，最后一个设备的索引号为DeviceCount-1；INT_PTR在32位的程序里面可以看成是int类型</param>
        /// <returns>返回非0表明打开设备成功，返回值表示打开的设备句柄；返回0表明打开设备失败；</returns>
        public static int OpenDevice(int nDeviceIndex)
        {
            return TeleDll.OpenDevice(nDeviceIndex);
        }

        /// <summary>
        /// 获取USB设备状态
        /// </summary>
        /// <param name="pDeviceHandle">这里的设备句柄就是OpenDevice时所返回的设备句柄;设备打开以后，未关闭就拔出，调用这个函数就会返回设备异常，这个时候就需要关闭设备，然后重新打开设备。</param>
        /// <returns>返回0表示设备正常，返回非0表明设备状态异常，代码为异常代码，错误代码参考上面网站链接</returns>
        public static int GetDeviceStatus(int pDeviceHandle)
        {
            return TeleDll.GetDeviceStatus(pDeviceHandle);
        }

        /// <summary>
        /// 关闭USB设备
        /// </summary>
        /// <param name="pDeviceHandle">这里的设备句柄就是OpenDevice时所返回的设备句柄</param>
        /// <returns>返回0表示关闭设备成功，其他值为错误代码，错误代码参考上面网站链接</returns>
        public static int CloseDevice(int pDeviceHandle)
        {
            pDeviceHandle = 0;
            return TeleDll.CloseDevice(pDeviceHandle);
        }

        /// <summary>
        /// 写数据，不公开调用
        /// </summary>
        /// <param name="pDeviceHandle"></param>
        /// <param name="szStr"></param>
        /// <returns></returns>
        private static int WriteStr(int pDeviceHandle, string szStr)
        {
            return TeleDll.WriteStr(pDeviceHandle, szStr);
        }

        /// <summary>
        /// 读数据，不公开调用
        /// </summary>
        private static int ReadStr(int pDeviceHandle, StringBuilder szStr, uint dwTimeoutMs)
        {
            return TeleDll.ReadStr(pDeviceHandle, szStr, dwTimeoutMs);
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="writeModel">写命令模型</param>
        /// <returns></returns>
        public static ReadModel Execute(WriteModel writeModel)
        {
            //LogInfo.LogOutput(LogInfo.log_info, "读写操作-top");
            Thread.Sleep(300);
            ReadModel readModel = new ReadModel();
            LogInfo.LogOutput(LogInfo.log_info, "写命令：command:" + writeModel.GetOrderStr());
            Console.WriteLine("command:" + writeModel.GetOrderStr());
            //Form1.Export_LogInfo("command:" + writeModel.GetOrderStr());
            readModel.TeleWriteCode = WriteStr(writeModel.PDeviceHandle, writeModel.GetOrderStr());
            if (readModel.TeleWriteCode != 0)
            {
                LogInfo.LogOutput(LogInfo.log_error, "写操作失败" + readModel.TeleWriteCode);
                readModel.Code = 1;
                return readModel;
            }
            Thread.Sleep(500);
            StringBuilder statusInfo = new StringBuilder(4097);
            readModel.TeleReadCode = ReadStr(writeModel.PDeviceHandle, statusInfo, writeModel.DwTimeoutMs);
            if (readModel.TeleReadCode != 0)
            {
                LogInfo.LogOutput(LogInfo.log_error, "读操作失败" + readModel.TeleReadCode);
                readModel.Code = 2;
                return readModel;
            }
            readModel.SetReadModel(statusInfo.ToString());
            LogInfo.LogOutput(LogInfo.log_info,"读命令:"+statusInfo.ToString());
            Console.WriteLine("feedBack:" + readModel.WriteFeedBack);
            //Form1.Export_LogInfo("feedBack:" + readModel.WriteFeedBack);
            //LogInfo.LogOutput(LogInfo.log_info, "读写操作-bottom");
            return readModel;
        }

       
    }
}
